﻿using LxBasic;
using System.Diagnostics;
using System.Text;
using System.Text.Json.Nodes;

namespace LxCore
{
    public class JsonTextReader : IJsonReader
    {
        public JsonTextReader(ITextReader jsonTextStream)
        {
            this.textStream = jsonTextStream;
        }
        protected ITextReader textStream;
        protected char CurrentChar;
        protected List<int> KeyCount = new List<int>();
        StringBuilder StringBuilder = new StringBuilder(20);
        int currentLine = 1;
        protected bool EndOfStream() => textStream.EndOfStream();
        protected char Peek() => CurrentChar = textStream.Peek();
        protected char Read() => CurrentChar = textStream.Read();
        protected void ReadLeftBracket(char left)
        {
            ReadExpectedChar(left);
            KeyCount.Add(0);
        }
        protected bool ReadSeperatorOrRightBracket(char right)
        {
            SkipWhiteSpace();
            if ((KeyCount[KeyCount.Count - 1]++) == 0)
            {
                if (Peek() == right)
                {
                    Read();
                    KeyCount.RemoveAt(KeyCount.Count - 1);
                    return false;
                }
                else
                {
                    return true;
                }
            }
            else
            {
                char c = Read();
                if (c == right)
                {
                    KeyCount.RemoveAt(KeyCount.Count - 1);
                    return false;
                }
                else if (c == ',')
                {
                    return true;
                }
                else
                {
                    throw GetException();
                }
            }
        }
        protected void SkipWhiteSpace()
        {
            while (true)
            {
                switch (Peek())
                {
                    case '\n':
                        currentLine++;
                        Read();
                        continue;
                    case ' ':
                    case '\t':
                    case '\r':
                    case '\v':
                    case '\f':
                        Read();
                        continue;
                    case '/'://注释
                        Read();
                        switch (Read())
                        {
                            case '/':
                                while (Read() != '\n') { }
                                break;
                            case '*':
                                char last2 = ' ', last1 = ' ';
                                while (true)
                                {
                                    last2 = last1;
                                    last1 = Read();
                                    if (last1 == '/' && last2 == '*')
                                    {
                                        break;
                                    }
                                }
                                break;
                            default:
                                throw GetException();
                        }
                        continue;
                    default:
                        return;
                }
            }
        }
        protected Exception GetException()
        {
            return new Exception($"无法解析的文本,line:{currentLine},char:{CurrentChar}");
        }
        public bool CheckNull()
        {
            SkipWhiteSpace();
            switch (Peek())
            {
                case 'N':
                case 'n':
                    Read();
                    if (Read() == 'u' && Read() == 'l'
                        && Read() == 'l')
                        return true;
                    else
                        throw GetException();
                default:
                    return false;
            }
        }
        public bool ReadBool()
        {
            SkipWhiteSpace();
            switch (Read())
            {
                case 't':
                    if (Read() == 'r' && Read() == 'u'
                        && Read() == 'e')
                        return true;
                    else
                        break;
                case 'f':
                    if (Read() == 'a' && Read() == 'l'
                        && Read() == 's' && Read() == 'e')
                        return false;
                    else
                        break;
            }
            throw GetException();
        }
        public int ReadInt()
        {
            return (int)ReadDouble();
        }
        public double ReadDouble()
        {
            StringBuilder sb = StringBuilder;
            sb.Clear();
            SkipWhiteSpace();
            while (true)
            {
                char c = Peek();
                switch (c)
                {
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                    case '-':
                    case '+':
                    case '.':
                    case 'e':
                    case 'E':
                        Read();
                        sb.Append(c);
                        break;
                    default:
                        return double.Parse(sb.ToString());
                }
            }
        }
        private string ReadArrayStringQuick()
        {
            ReadExpectedChar('[');
            StringBuilder sb = StringBuilder;
            sb.Clear();
            for (; ; )
            {
                char ch = Read();
                if (ch == ']')
                {
                    return sb.ToString();
                }
                else
                {
                    sb.Append(ch);
                }
            }
        }
        public string ReadArrayString()
        {
            ReadExpectedChar('[');
            StringBuilder sb = StringBuilder;
            sb.Clear();
            sb.Append('[');
            int count = 1;
            for (; ; )
            {
                SkipWhiteSpace();
                char ch = Read();
                sb.Append(ch);
                switch (ch)
                {
                    case '"':
                        char temp = default;
                        do
                        {
                            temp = Read();
                            sb.Append(temp);
                            if (temp == '\\')
                            {
                                sb.Append(Read());
                            }
                        } while (temp != '"');
                        break;
                    case '[':
                        count++;
                        break;
                    case ']':
                        count--;
                        if (count < 1)
                        {
                            return sb.ToString();
                        }
                        break;
                }
            }
        }
        public string ReadObjectString()
        {
            ReadExpectedChar('{');
            StringBuilder sb = StringBuilder;
            sb.Clear();
            sb.Append('{');
            int count = 1;
            for (; ; )
            {
                SkipWhiteSpace();
                char ch = Read();
                sb.Append(ch);
                switch (ch)
                {
                    case '"':
                        char temp = default;
                        do
                        {
                            temp = Read();
                            sb.Append(temp);
                            if (temp == '\\')
                            {
                                sb.Append(Read());
                            }
                        } while (temp != '"');
                        break;
                    case '{':
                        count++;
                        break;
                    case '}':
                        count--;
                        if (count < 1)
                        {
                            return sb.ToString();
                        }
                        break;
                }
            }
        }
        public string ReadString()
        {
            SkipWhiteSpace();
            if (Read() != '"') throw GetException();
            StringBuilder sb = StringBuilder;
            sb.Clear();
            for (; ; )
            {
                char ch = Read();
                switch (ch)
                {
                    case '"':
                        return sb.ToString();
                    case '\\':
                        char next = Read();
                        switch (next)
                        {
                            case '"': sb.Append('"'); break;
                            case '\\': sb.Append('\\'); break;
                            default: sb.Append(ch).Append(next); break;
                        }
                        break;
                    default:
                        sb.Append(ch);
                        break;
                }
            }
        }
        public string ReadKey()
        {
            string key = ReadString();
            ReadExpectedChar(':');
            return key;
        }
        public Vector3d ReadVector3d()
        {
            ReadExpectedChar('[');
            StringBuilder sb = StringBuilder;
            sb.Clear();
            sb.Append('[');
            for (; ; )
            {
                char ch = Read();
                sb.Append(ch);
                if (ch == ']')
                {
                    return Vector3d.Parse(sb.ToString());
                }
            }
        }

        public TEnum ReadEnum<TEnum>() where TEnum : struct
        {
            string str = ReadString();
            return Enum.Parse<TEnum>(str);
        }
        public void ReadObject<T>(T jsonObject, Action<T> setValue = null, Func<Type, T> createValue = null) where T : JsObject
        {
            if (setValue == null)
            {
                ReadLeftBracket('{');
                while (ReadSeperatorOrRightBracket('}'))
                {
                    jsonObject.FromJsonKV(ReadKey(), this);
                }
            }
            else
            {
                if (CheckNull())
                {
                    if (jsonObject != null)
                    {
                        setValue(null);
                    }
                }
                else
                {
                    ReadLeftBracket('{');
                    string type = null;
                    bool head = true;
                    while (ReadSeperatorOrRightBracket('}'))
                    {
                        string key = ReadKey();
                        if (head && key.StartsWith('-'))
                        {
                            switch (key)
                            {
                                case "-Type":
                                    type = ReadString();
                                    break;
                                default: throw new InvalidDataException("未定义的行为");
                            }
                        }
                        else
                        {
                            if (head)
                            {
                                head = false;
                                if (jsonObject == null)
                                {
                                    if (createValue == null && type != null)
                                    {
                                        jsonObject = Activator.CreateInstance(Type.GetType(type)) as T;
                                    }
                                    else
                                    {
                                        jsonObject = createValue(type == null ? null : Type.GetType(type));
                                    }
                                    setValue(jsonObject);
                                }
                            }
                            jsonObject.FromJsonKV(key, this);
                        }

                    }
                }
            }
        }

        public void ReadList<T>(JsList<T> jsonArray, Func<Type, T> createValue) where T : JsObject
        {
            ReadLeftBracket('[');
            while (ReadSeperatorOrRightBracket(']'))
            {
                ReadLeftBracket('{');
                int idx = -1;
                string name = null;
                T tar = null;
                string type = null;
                bool head = true;
                while (ReadSeperatorOrRightBracket('}'))
                {
                    string key = ReadKey();
                    if (head && key.StartsWith('-'))
                    {
                        switch (key)
                        {
                            case "-Index":
                                idx = ReadInt();
                                break;
                            case "-Name":
                                name = ReadString();
                                break;
                            case "-Type":
                                type = ReadString();
                                break;
                            default: throw new InvalidDataException("未定义的行为");
                        }
                    }
                    else
                    {
                        if (head)
                        {
                            head = false;
                            if (idx == -1 && !string.IsNullOrEmpty(name) && jsonArray is IIdentityList jsidl)
                            {
                                idx = jsidl.IndexOf(name);
                            }
                            if (idx >= 0 && idx < jsonArray.Count)
                            {
                                tar = jsonArray[idx];
                            }
                            else
                            {
                                jsonArray.Add(createValue.Invoke(type == null ? null : Type.GetType(type)));
                                tar = jsonArray[jsonArray.Count - 1];
                            }
                        }
                        tar.FromJsonKV(key, this);
                    }
                }
            }
        }
        public void ReadExpectedChar(char c)
        {
            SkipWhiteSpace();
            if (Read() != c)
            {
                throw GetException();
            }
        }
        protected void ReadArray<T>(T[] array, Action<T[]> setValue, Func<T> readElement)
        {
            if (CheckNull())
            {
                setValue(null);
            }
            else
            {
                ReadExpectedChar('[');
                int length = ReadInt();
                if (array == null || array.Length != length)
                {
                    array = new T[length];
                    setValue(array);
                }
                for (int i1 = 0; i1 < length; i1++)
                {
                    ReadExpectedChar(',');
                    array[i1] = readElement();
                }
                ReadExpectedChar(']');
            }
        }
        public void ReadIntArray(int[] ints, Action<int[]> setValue)
        {
            ReadArray(ints, setValue, ReadInt);
        }
        public void ReadDoubleArray(double[] doubleArray, Action<double[]> setValue)
        {
            ReadArray(doubleArray, setValue, ReadDouble);
        }

        public void ReadVector3dArray(Vector3d[] vectorArray, Action<Vector3d[]> setValue)
        {
            ReadArray(vectorArray, setValue, ReadVector3d);
        }

        public void ReadInnFaceArray(FvInnFace[] faces, Action<FvInnFace[]> setValue)
        {
            ReadArray(faces, setValue, () =>
            {
                string str = ReadArrayStringQuick();
                string[] ss = str.Split(',');
                FvInnFace f = new FvInnFace();
                f.Nodes = new int[ss.Length - 2];
                for (int i1 = 0; i1 < f.Nodes.Length; i1++)
                {
                    f.Nodes[i1] = int.Parse(ss[i1]);
                }
                f.OSideCell = int.Parse(ss[ss.Length - 2]);
                f.NSideCell = int.Parse(ss[ss.Length - 1]);
                return f;
            });
        }

        public void ReadBouFaceArray(FvBouFace[] bFaces, Action<FvBouFace[]> setValue)
        {
            ReadArray(bFaces, setValue, () =>
            {
                string str = ReadArrayStringQuick();
                string[] ss = str.Split(',');
                FvBouFace f = new();
                f.Nodes = new int[ss.Length - 1];
                for (int i1 = 0; i1 < f.Nodes.Length; i1++)
                {
                    f.Nodes[i1] = int.Parse(ss[i1]);
                }
                f.OSideCell = int.Parse(ss[ss.Length - 1]);
                return f;
            });
        }
        public IndexRange ReadIndexRange()
        {
            ReadExpectedChar('[');
            IndexRange ir = new();
            ir.Start = ReadInt();
            ReadExpectedChar(',');
            ir.End = ReadInt();
            ReadExpectedChar(']');
            return ir;
        }

        public void ReadVector2dArray(Vector2d[] vectorArray, Action<Vector2d[]> setValue)
        {
            ReadArray(vectorArray, setValue, () =>
            {
                ReadExpectedChar('[');
                StringBuilder sb = StringBuilder;
                sb.Clear();
                sb.Append('[');
                for (; ; )
                {
                    char ch = Read();
                    sb.Append(ch);
                    if (ch == ']')
                    {
                        return Vector2d.Parse(sb.ToString());
                    }
                }
            });
        }

        public void ReadMonitorSelector(UserMonitor m)
        {
            ReadLeftBracket('[');
            while (ReadSeperatorOrRightBracket(']'))
            {
                string totalPath = ReadString();
                string[] paths = totalPath.Split(':');
                if (paths.Length == 0) continue;
                FvZone z = ResHelper.GetZone(paths[0]);
                if (z == null) continue;
                if (paths.Length == 1)
                {
                    m.SetSelector(z.Inner, true);
                }
                else
                {
                    FvBound b = ResHelper.GetBound(z, paths[1]);
                    if (b == null) continue;
                    m.SetSelector(b, true);
                }
            }
        }

        public void ReadGraphSelector(Graph g)
        {
            ReadLeftBracket('[');
            while (ReadSeperatorOrRightBracket(']'))
            {
                string totalPath = ReadString();
                string[] paths = totalPath.Split(':');
                if (paths.Length == 0) continue;
                FvZone z = ResHelper.GetZone(paths[0]);
                if (z == null) continue;
                if (paths.Length == 1)
                {
                    g.SetSelector(z.Inner, true);
                }
                else
                {
                    FvBound b = ResHelper.GetBound(z, paths[1]);
                    if (b == null) continue;
                    g.SetSelector(b, true);
                }
            }
        }
    }
}
//if (head)
//{
//    head = false;
//    if (string.Equals(key, "-Type"))
//    {
//        Type type = Type.GetType(ReadString());
//        if (type == null)
//        {
//            throw new InvalidDataException("未找到相应Type");
//        }
//        if (jsonObject == null || jsonObject.GetType() != type)
//        {
//            setValue(createValue == null ? Activator.CreateInstance(type) as T : createValue(type));
//        }
//        continue;
//    }
//    if (jsonObject == null)
//    {
//        setValue(createValue(null));
//    }
//}
//jsonObject.FromJsonKV(key, this);